﻿using Sidvall.Web.IO.Data;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;

namespace Sidvall.Web.IO
{
    public class ControllerManager : Sidvall.Web.ControllerManager
    {
        #region Public Members

        #region GetStreamContent

        public HttpResponseMessage GetStreamContent(ApiController controller, System.IO.Stream stream, string fileName, string contentType, int? length, long? position)
        {
            ContentInfo contentInfo;

            if (stream == null)
                throw new System.ArgumentNullException(nameof(stream));
            if ((length != null) && (position != null))
                contentInfo = ContentInfo.Parse(stream.Length, length.Value, position.Value);
            else
                contentInfo = ContentInfo.Parse(stream.Length, controller.Request.Headers?.Range);
            if (contentInfo.IsMultipartRequest)
                throw new System.NotSupportedException("Multipart request not supported");
            var message = new HttpResponseMessage();
            if (contentInfo.IsRangeRequest)
            {
                var partialStream = new PartialStream(stream, contentInfo.Ranges.First());
                message.Content = new StreamContent(partialStream, Sidvall.IO.NetSystemContext.Current.DefaultBufferSize);
                SetResponseHeaders(message, fileName, contentType, partialStream.Length, contentInfo);
            }
            else
            {
                message.Content = new StreamContent(stream, Sidvall.IO.NetSystemContext.Current.DefaultBufferSize);
                SetResponseHeaders(message, fileName, contentType, stream.Length, contentInfo);
            }
            return message;
        }

        #endregion
        #region GetStreamContentAsync

        public async Task<HttpResponseMessage> GetStreamContentAsync(ApiController controller, string path, string contentType, string storeId)
        {
            return await GetStreamContentAsync(controller, path, contentType, storeId, null, null);
        }
        public async Task<HttpResponseMessage> GetStreamContentAsync(ApiController controller, string path, string contentType, string storeId, int? length, long? position)
        {
            System.IO.Stream stream;

            if (string.IsNullOrWhiteSpace(path))
                throw new System.ArgumentNullException(nameof(path));

            stream = null;
            try
            {
                stream = await SystemContext.Current.FileManager.OpenFileAsync(storeId, OpenFileContext.Create(path), Sidvall.IO.FileMode.Open,
                   Sidvall.IO.FileAccess.Read, CancellationToken.None);
                return GetStreamContent(controller, stream, System.IO.Path.GetFileName(path), contentType, length, position);
            }
            catch (System.Exception ex)
            {
                if (stream != null)
                {
                    stream.Dispose();
                    stream = null;
                }
                await SystemContext.Current.ControllerManager.LogAsync(ex);
                return SystemContext.Current.ControllerManager.GetResponseMessage(controller, ex);
            }
        }

        #endregion
        #region SetResponseHeaders

        public void SetResponseHeaders(HttpResponseMessage response, string fileName, string contentType, long contentLength, HttpStatusCode statusCode)
        {
            response.Headers.AcceptRanges.Add("bytes");
            response.StatusCode = statusCode;
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            response.Content.Headers.ContentDisposition.FileName = fileName;
            if (string.IsNullOrWhiteSpace(contentType))
                contentType = Sidvall.Net.Mime.MediaTypeManager.GetMediaTypeNameFromFileExtension(System.IO.Path.GetExtension(fileName));
            response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
            response.Content.Headers.ContentLength = contentLength;
        }
        public void SetResponseHeaders(HttpResponseMessage response, string fileName, string contentType, long fileLength, ByteRange item)
        {
            SetResponseHeaders(response, fileName, contentType, item.Length, HttpStatusCode.PartialContent);
            response.Content.Headers.ContentRange = new ContentRangeHeaderValue(item.From, item.To, fileLength);
        }
        public void SetResponseHeaders(HttpResponseMessage response, string fileName, string contentType, long fileLength, ContentInfo contentInfo)
        {
            if (contentInfo.IsMultipartRequest)
                throw new System.NotSupportedException("Multipart request not supported");
            if (contentInfo.IsRangeRequest)
                SetResponseHeaders(response, fileName, contentType, fileLength, contentInfo.Ranges.First());
            else
                SetResponseHeaders(response, fileName, contentType, fileLength, HttpStatusCode.OK);
        }
        public void SetResponseHeaders(HttpResponseMessage response, string fileName, string contentType, long fileLength, long entityLength,
            System.Net.Http.Headers.RangeHeaderValue rangeHeader)
        {
            if (response.Content == null)
                response.Content = new ByteArrayContent(new byte[0]);
            var contentInfo = ContentInfo.Parse(fileLength, rangeHeader);
            SetResponseHeaders(response, fileName, contentType, fileLength, contentInfo);
        }

        #endregion

        #endregion
    }
}
